HCP Vaultで一時的なAWSアクセスキーを発行してTerraformを実行してみる
「ローカルに永続的なAWSアクセスキーを持たずに、Terraformを実行したい」
AWS IAM Identity Centerで一時的なアクセスキーを発行するとか、Terraform CloudのVariablesにAWSアクセスキー置く(IAM Role使う)とか色々方法があります。
今回はHCP Vaultを使ってみます。
HCP Vaultとは
Vaultはシークレット管理ソリューションです。クレデンシャル等をセキュアに管理します。
Vaultはセルフホスト版とSaaS版があります。
セルフホスト版は柔軟性が高いことはメリットですが、サーバーの管理が必要になります。
HCP VaultはSaaS版で、Vaultクラスターに必要なサーバーの管理をHashiCorpが行います。
クラスターをデプロイするクラウドプロパイダーはAWSとAzureから選択可能で、日本リージョン(AWSならap-northeast-1)をサポートしています。
HCP Vault Overview | HashiCorp Cloud Platform | HashiCorp Developer
やってみた
作成する構成は以下です。
HCP Vaultで一時的なAWSアクセスキーを作成して、Terraformでそれを使ってAWSにリソースをデプロイしてみます。
HCP VaultやVaultの設定もTerraformを使います。
コードはGitHubにあります。
terraform-sample/hcp-vault-terraform at main · msato0731/terraform-sample
HCP Service Principalの作成
Vault ClusterをTerraformで作成します。
TerraformでHCPのリソースを操作するために、Service Principalを作成する必要があります。
Authenticate with HCP - HCP Provider | Guides | hashicorp/hcp | Terraform | Terraform Registry
HCPポータルにログインして、Access Control(IAM)
-> Service principals
-> Create service principal
の順に選択します。
名前とRoleを設定してService principalを作成します。
Generate key
を選択して、キーを作成します。Client ID
とClient secret
の内容を控えておきます。
HCP Vault Clusterの作成
Terraformを使用して、HCP Vault Clusterを作成します。
ターミナルを開いて、先ほど作成したキーを環境変数に設定します。
export HCP_CLIENT_ID="<Service Principal Clinet ID>" export HCP_CLIENT_SECRET="<Service Principal Clinet Secrets>"
以下のファイルを使います。
terraform { required_providers { hcp = { source = "hashicorp/hcp" version = "0.79.0" } } } terraform { backend "local" { path = "terraform.tfstate" } } resource "hcp_hvn" "main" { hvn_id = "hvn1" cloud_provider = "aws" region = "ap-northeast-1" cidr_block = "172.25.16.0/20" } resource "hcp_vault_cluster" "main" { cluster_id = "vault-cluster" hvn_id = hcp_hvn.main.hvn_id tier = "dev" public_endpoint = true } resource "hcp_vault_cluster_admin_token" "main" { cluster_id = hcp_vault_cluster.main.cluster_id }
上記tfファイルがあるディレクトリに移動し、コマンドを実行して、リソースを作成します。
terraform init terraform apply
Vault Clusterが作成できたら、Web UIでアクセスできるか確認します。
New admin token
からGenerate Token
->Copy
を選択して、Tokenを取得します。
ページ上部の、Launch web UI
を選択します。
Token入力が求めれるため、先ほどのTokenを入力します。
以下のようにVaultのWeb UIにアクセスできます。
Vault用のIAMユーザー作成
Vaultは一時的なIAMアクセスキーを作成します。
その際に、Vaultが利用するIAMユーザーが必要です。
CloudShellまたは、ローカルからAWS CLIを実行して、IAMユーザーを作成します。
aws iam create-user --user-name vault-user
必要なIAM権限を公式ドキュメントを参考にします。ポリシーは以下です。 (ハイライト箇所のACCOUNT-IDの部分は、それぞれ置き換えてください。)
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iam:AttachUserPolicy", "iam:CreateAccessKey", "iam:CreateUser", "iam:DeleteAccessKey", "iam:DeleteUser", "iam:DeleteUserPolicy", "iam:DetachUserPolicy", "iam:GetUser", "iam:ListAccessKeys", "iam:ListAttachedUserPolicies", "iam:ListGroupsForUser", "iam:ListUserPolicies", "iam:PutUserPolicy", "iam:AddUserToGroup", "iam:RemoveUserFromGroup" ], "Resource": ["arn:aws:iam::ACCOUNT-ID-WITHOUT-HYPHENS:user/vault-*"] } ] }
以下のコマンドを実行して、ポリシーを割り当てます。
aws iam put-user-policy --user-name vault-user --policy-name vault --policy-document file://policy.json
Vaultにセットするアクセスキーを作成します。
aws iam create-access-key --user-name vault-user
アクセスキーIDとシークレットアクセスキーは、次の手順で利用するため控えておいてください。
AWS - Secrets Engines | Vault | HashiCorp Developer
Vaultの設定
Terraformを使って、Vaultの設定を行います。
TerraformからVaultを操作するために、Token等を環境変数に設定していきます。
先ほどWeb UIにアクセスした時と同様に、Tokenをコピーしてセットします。
export VAULT_TOKEN=<Vault Token>
ClusterのPublic URLもセットします。Cluster URLs
-> Public
を選択して、取得します。
export VAULT_ADDR=<Vault Public Cluster URL>
以下のファイルを使います。
variable "aws_access_key" {} variable "aws_secret_key" {} variable "name" { default = "dynamic-aws-creds-vault-admin" } terraform { required_providers { vault = { source = "hashicorp/vault" version = "3.23.0" } } } terraform { backend "local" { path = "terraform.tfstate" } } resource "vault_aws_secret_backend" "aws" { access_key = var.aws_access_key secret_key = var.aws_secret_key path = "${var.name}-path" default_lease_ttl_seconds = "120" max_lease_ttl_seconds = "240" } resource "vault_aws_secret_backend_role" "admin" { backend = vault_aws_secret_backend.aws.path name = "${var.name}-role" credential_type = "iam_user" policy_document = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iam:*", "ec2:*", "s3:*" ], "Resource": "*" } ] } EOF } output "backend" { value = vault_aws_secret_backend.aws.path } output "role" { value = vault_aws_secret_backend_role.admin.name }
上記tfファイルがあるディレクトリに移動し、コマンドを実行して、リソースを作成します。
実行時にAWSアクセスキーIDとシークレットアクセスキーが求められるため、前の手順で作成したものを入力してください。
terraform init terraform apply
成功するとVault上にSecrets engines dynamic-aws-creds-vault-admin-path
が作成されます。
AWSリソースのデプロイ
Vaultを使ってローカルの認証情報を使わずにTerraformでAWSリソースをデプロイしてみます。
以下のファイルを使います。
terraform { required_providers { aws = { source = "hashicorp/aws" version = "5.31.0" } vault = { source = "hashicorp/vault" version = "3.23.0" } } } terraform { backend "local" { path = "terraform.tfstate" } } data "terraform_remote_state" "vault" { backend = "local" config = { path = "../vault/terraform.tfstate" } } data "vault_aws_access_credentials" "creds" { backend = data.terraform_remote_state.vault.outputs.backend role = data.terraform_remote_state.vault.outputs.role } provider "aws" { region = "ap-northeast-1" access_key = data.vault_aws_access_credentials.creds.access_key secret_key = data.vault_aws_access_credentials.creds.secret_key } resource "aws_s3_bucket" "main" { bucket = "vault-test-20240105" # 一意な名前を指定してください }
ハイライト箇所の記述で、VaultからAWS認証情報を取得しています。記述がシンプルでいいですね。
Vaultで一時的なAWSアクセスキーを作成してTerraformを実行するため、ローカルのAWSアクセスキーは不要です。
ローカルの認証情報が使われないように、一応環境変数から消しておきます。
unset AWS_ACCESS_KEY_ID unset AWS_SECRET_ACCESS_KEY unset AWS_SESSION_TOKEN
上記tfファイルがあるディレクトリに移動し、コマンドを実行して、リソースを作成します。
terraform init terraform apply
Applyが終わるとS3バケットが作成されました。
$ aws s3 ls | grep vault 2024-01-05 08:30:13 vault-test-20240105
IAMユーザーも見てみます。Vaultによって作成される一時的なIAMユーザーを確認できました。
このユーザーは、Vaultで設定したTTLに従ってTerraform実行後に削除されます。
おわりに
HCP Vaultで一時的なAWS認証情報を作成して、Terraformから使ってみました。
HCP VaultはSaaS製品でTerraformのhcpプロパイダーで操作可能なため、簡単にVault Clusterを作成できました。(コード量もHCPとVault合わせて、100行いかないくらいでした)
以上、AWS事業本部の佐藤(@chari7311)でした。